using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Jonathan.SharpDB;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Xml;
//using mshtml;

namespace Jonathan
{
	/// <summary>
	/// An extended WebBrowser.
	/// </summary>
    public class Webber : WebBrowser
	{
		#region - Fields -

		private string m_HTML;
        private frmMain m_FormMain;
        private IWebberHost m_Host;
        private fHtmlToolTip m_MOToolTip;
        private bool m_TTShown;
        private HtmlElement m_MouseClickElement;

		#endregion

		#region - Constructor / Setup -

		/// <summary>
		/// Creates a new Webber Control.
		/// </summary>
		public Webber()
		{
			this.Navigate("about:Blank");
			while (this.Document.Body == null) Application.DoEvents();
			this.m_HTML = "";
        }

		/// <summary>
		/// Sets up the Webber Control.
		/// </summary>
		/// <param name="main">Reference to Main From.</param>
		/// <param name="host">The Control that hosts this webber.</param>
		public void SetupWebber (frmMain main, IWebberHost host)
		{
			this.m_FormMain = main;
			this.m_Host = host;
			if (host != null)
			{
				this.ContextMenuStrip = host.GetContextMenu();
			}
			this.m_MOToolTip = null;
			this.m_TTShown = false;

			this.Document.MouseUp += new HtmlElementEventHandler(Document_MouseUp);
			this.Document.MouseDown += new HtmlElementEventHandler(Document_MouseDown);
			this.Document.MouseOver += new HtmlElementEventHandler(Document_MouseOver);
			this.Resize += new EventHandler(Webber_Resize);

			this.AllowNavigation = false;
			this.AllowWebBrowserDrop = false;
			this.IsWebBrowserContextMenuEnabled = false;
		}

		/// <summary>
		/// Occurs when the WebBrowser is resized.
		/// </summary>
		/// <param name="sender">WebBrowser (this).</param>
		/// <param name="e">Event Arguments.</param>
		void Webber_Resize (object sender, EventArgs e)
		{
			if (this.Document != null)
				this.Document.InvokeScript("resizeJonathan");
		}

        #endregion

        #region - Mouse Over -

        /// <summary>
        /// Occurs when the mouse is over the document...
        /// </summary>
        /// <param name="sender">Document</param>
        /// <param name="e">HtmlElementEventArgs</param>
        void Document_MouseOver (object sender, HtmlElementEventArgs e)
        {
            if (this.m_FormMain.ProgramData.MouseOverToolTips)
            {
                if (e.ToElement != null)
                {
                    if (e.ToElement.TagName.Equals("A"))
					{
                        if (Common.isNumeric(e.ToElement.InnerText))
                        {
							this.ShowStrongsTT(e, true);
                        }
                        else if (e.ToElement.InnerText.StartsWith("see GREEK"))
                        {
                            string num = e.ToElement.InnerText.Substring(e.ToElement.InnerText.LastIndexOf(' ') + 1);
                            num = num.TrimStart(new char[] { '0' });
                            CreateStrongsTT(e, num, "Greek", true);
                        }
                        else if (e.ToElement.InnerText.StartsWith("see HEBREW"))
                        {
                            string num = e.ToElement.InnerText.Substring(e.ToElement.InnerText.LastIndexOf(' ') + 1);
                            num = num.TrimStart(new char[] { '0' });
                            CreateStrongsTT(e, num, "Hebrew", true);
                        }
                        else if (e.ToElement.OuterHtml.IndexOf("<A href=\"wordref\">") == 0)
                        {
                            this.CloseTT();
						}
						else if (e.ToElement.OuterHtml.Contains("class=goto"))
                        {
                            this.CloseTT();
                        }
                        else
                        {
                            CreateMOScriptureTT(e.ToElement, e);
                        }
                    }
                    else
                    {
                        this.CloseTT();
                    }
                }
            }
        }

        #endregion

        #region - Close ToolTip -

        /// <summary>
        /// Close the Tool Tip if Open...
        /// </summary>
        private void CloseTT ()
        {
            if (this.m_TTShown)
            {
                this.m_MOToolTip.Close();
                this.m_MOToolTip.Dispose();
                this.m_MOToolTip = null;
                this.m_TTShown = false;
            }
        }

        #endregion

		#region - Mouse Down -

		/// <summary>
        /// Occurs when the mouse is released...
        /// </summary>
        /// <param name="sender">Document</param>
        /// <param name="e">HtmlElementEventArgs</param>
        void Document_MouseDown (object sender, HtmlElementEventArgs e)
        {
			if (e.MouseButtonsPressed == MouseButtons.Right)
			{
				this.m_MouseClickElement = this.ActiveElement;
				if (this.Selection.Equals(string.Empty) && !this.ActiveElement.TagName.Equals("TEXTAREA"))
					this.SelectWord();
			}

			if (this.m_Host.GetType() == typeof(ctrlSearch))
			{
				HtmlElement hel = this.Document.GetElementFromPoint(e.MousePosition);
				if (hel != null)
				{
					if (e.MouseButtonsPressed == MouseButtons.Left)
						this.HighlightRow(hel, e.CtrlKeyPressed, false);
					else if (!e.CtrlKeyPressed)
						this.HighlightRow(hel, false, true);
				}
			}
		}

		#endregion

		#region - Mouse Up -

		/// <summary>
        /// Occurs when the mouse is released...
        /// </summary>
        /// <param name="sender">Document</param>
        /// <param name="e">HtmlElementEventArgs</param>
        void Document_MouseUp (object sender, HtmlElementEventArgs e)
        {
            if (e.MouseButtonsPressed == MouseButtons.Left)
            {
                if (this.ActiveElement.TagName.Equals("A"))
				{
					XmlDocument xDoc = GetXMLDoc();
					XmlAttribute hrefAtt = xDoc.ChildNodes[0].Attributes["href"];

                    if (Common.isNumeric(xDoc.InnerText))
                    {
						this.ShowStrongsTT(e, false);
                    }
					else if (xDoc.InnerText.StartsWith("see GREEK"))
                    {
						string num = xDoc.InnerText.Substring(xDoc.InnerText.LastIndexOf(' ') + 1);
                        num = num.TrimStart(new char[] { '0' });
                        CreateStrongsTT(e, num, "Greek", false);
                    }
					else if (xDoc.InnerText.StartsWith("see HEBREW"))
                    {
						string num = xDoc.InnerText.Substring(xDoc.InnerText.LastIndexOf(' ') + 1);
                        num = num.TrimStart(new char[] { '0' });
                        CreateStrongsTT(e, num, "Hebrew", false);
                    }
					else if (hrefAtt != null)
					{
						XmlAttribute classAtt = xDoc.ChildNodes[0].Attributes["class"];
						if (hrefAtt.Value.Equals("wordref", StringComparison.CurrentCultureIgnoreCase))//this.ActiveElement.OuterHtml.IndexOf("<A href=\"wordref\">") == 0)
						{
							if (this.m_Host != null)
							{
								if (e.CtrlKeyPressed)
								{
									this.m_FormMain.StartReference(this.m_Host.GetVersion(0), xDoc.InnerText, this.m_Host.GetTabPage());
								}
								else
								{
									bool selected = this.m_Host.SelectRefWord(xDoc.InnerText, false);
									// This is for easton's BD, sometimes we will have a word that ends in 's', and the word in the list will not...
									if (!selected && xDoc.InnerText.ToLower().EndsWith("s"))
										selected = this.m_Host.SelectRefWord(xDoc.InnerText.Substring(0, xDoc.InnerText.Length - 1), false);
									// This is for easton's BD, sometimes the ref word does not match the word in the list correctly...
									if (!selected)
										this.m_Host.SelectRefWord(xDoc.InnerText, true);
								}
							}
						}
						else if (classAtt != null)
						{
							if (classAtt.Value.Equals("goto", StringComparison.CurrentCultureIgnoreCase))
							{
								string pass = xDoc.ChildNodes[0].Attributes["title"].Value;
								List<cPassage> passages = cParser.Parse(pass.Substring(pass.IndexOf(' ')).Trim());
								if (passages.Count > 0)
								{
									passages[0].Version = hrefAtt.Value;
									this.m_FormMain.StartBible(passages, null);

									if (this.m_Host.GetType() == typeof(fHtmlToolTip))
									{
										fHtmlToolTip tt = (fHtmlToolTip)this.m_Host;
										tt.Close();
									}
								}
							}
						}
						else
						{
							CreateScriptureTT(e);
						}
					}
                }
                else if(this.ActiveElement.OuterText != null && this.ActiveElement.OuterText.Equals("TSK"))
                {
					this.ToggleTSK();
                }
                else if (this.ActiveElement.TagName.Equals("BUTTON"))
                {
					SaveVerseNotes();

                }
            }
		}

		#endregion

		#region - Show Strong's Tool Tip -

		/// <summary>
		/// Shows a Tool Tip of a Strong's number.
		/// </summary>
		/// <param name="e">HtmlElementEventArgs</param>
		/// <param name="mouseOver">Is this on a mouse over action or not.</param>
		private void ShowStrongsTT (HtmlElementEventArgs e, bool mouseOver)
		{
			HtmlElement elTR = Common.GetTRElement(this);
			int index = 0;
			string book = "";
			if ((index = elTR.OuterHtml.IndexOf("passage")) != -1)
			{
				string passage = elTR.OuterHtml.Substring(index + 9, elTR.OuterHtml.IndexOf(">") - 10 - index);
				book = passage.Split('|')[0];
			}
			if (!string.IsNullOrEmpty(book))
			{
				if (cParser.IsBookNewTestament(book))
				{
					CreateStrongsTT(e, this.ActiveElement.InnerText, "Greek", mouseOver);
				}
				else
				{
					CreateStrongsTT(e, this.ActiveElement.InnerText, "Hebrew", mouseOver);
				}
			}
		}

		#endregion

		#region - Save Verse Notes -

		/// <summary>
		/// Saves the Notes of a specific verse.
		/// </summary>
		private void SaveVerseNotes ()
		{
			HtmlElement hDiv = this.ActiveElement.Parent;
			int index = 0;
			string dest = "";
			if ((index = hDiv.OuterHtml.IndexOf("id")) != -1)
				dest = hDiv.OuterHtml.Substring(index + 3, hDiv.OuterHtml.IndexOf(">") - 3 - index);

			string[] noteInfo = dest.Split('|');

			Database dbVerseNotes = new Database(Common.DATA_FOLDER + Common.DATABASE_VERSE_NOTES);
			Query qVerseNotes = new Query(QueryType.SELECT, Common.TABLE_NOTES);
			qVerseNotes.SELECT("Verse");
			qVerseNotes.SELECT("Note");
			qVerseNotes.WHERE("Book", Operator.EQUALS, noteInfo[1]);
			qVerseNotes.WHERE("Chapter", Operator.EQUALS, noteInfo[2]);
			qVerseNotes.WHERE("Verse", Operator.EQUALS, noteInfo[3]);
			dbVerseNotes.RunQuery(qVerseNotes);
			string note = hDiv.FirstChild.InnerText;

			if (qVerseNotes.RowsReturned == 0)
			{
				if (!string.IsNullOrEmpty(note))
				{
					ArrayList row = new ArrayList();
					row.Add(noteInfo[1]);
					row.Add(noteInfo[2]);
					row.Add(noteInfo[3]);
					row.Add(note);

					dbVerseNotes.Insert(Common.TABLE_NOTES, row);
				}
			}
			else
			{
				Query qUpdate;
				if (!string.IsNullOrEmpty(note))
				{
					qUpdate = new Query(QueryType.UPDATE, Common.TABLE_NOTES);
					qUpdate.SET("Note", note);
				}
				else
					qUpdate = new Query(QueryType.DELETE, Common.TABLE_NOTES);

				qUpdate.WHERE("Book", Operator.EQUALS, noteInfo[1]);
				qUpdate.WHERE("Chapter", Operator.EQUALS, noteInfo[2]);
				qUpdate.WHERE("Verse", Operator.EQUALS, noteInfo[3]);
				dbVerseNotes.RunQuery(qUpdate);
			}

			dbVerseNotes.Commit();
			hDiv.InnerHtml = note;
			if (string.IsNullOrEmpty(note))
				hDiv.Parent.Parent.Style = "DISPLAY: none";
		}

		#endregion

		#region - Toggle TSK -

		/// <summary>
		/// Toggles if the Treasury of Scripture Knowledge is shown or not.
		/// </summary>
		private void ToggleTSK ()
		{
			string oHtml = this.ActiveElement.InnerHtml;
			int index = 0;
			string dest = "";
			if ((index = oHtml.IndexOf("destina")) != -1)
				dest = oHtml.Substring(index + 9, oHtml.IndexOf(">") - 10 - index);

			if (!string.IsNullOrEmpty(dest))
			{
				HtmlElement destEL = this.Document.GetElementById(dest);
				if (destEL != null)
				{
					if (string.IsNullOrEmpty(destEL.InnerHtml))
					{
						string[] info = dest.Split('|');
						Database tsk = new Database(Common.DATA_FOLDER + this.m_FormMain.ProgramData.TSK.Path);
						Query qTsk = new Query(QueryType.SELECT, info[1]);
						qTsk.SELECT("Text");
						qTsk.WHERE("Chapter", Operator.EQUALS, info[2]);
						qTsk.WHERE("Verse", Operator.EQUALS, info[3]);

						tsk.RunQuery(qTsk);

						if (qTsk.RowsReturned > 0)
						{
							string tskText = qTsk.Results.GetFieldString(0, 0).Trim();
							destEL.Parent.Parent.Style = "DISPLAY: block";
							destEL.Parent.Parent.FirstChild.Style = "BACKGROUND: #D8D8D8";
							destEL.Parent.Parent.FirstChild.InnerHtml = "<span style=\"writing-mode: tb-rl;filter: flipv fliph;font-weight:bolder;\">TSK</span>";
							if (!string.IsNullOrEmpty(tskText))
								destEL.InnerHtml = qTsk.Results.GetFieldString(0, 0);
							else
								destEL.InnerHtml = "<strong>No references for this verse.</strong>";
						}
					}
					else
					{
						destEL.Parent.Parent.Style = "DISPLAY: none";
						destEL.Parent.Parent.FirstChild.Style = "BACKGROUND: #FCFDFE";
						destEL.Parent.Parent.FirstChild.InnerHtml = "";
						destEL.InnerHtml = "";
					}
				}
			}
		}

		#endregion

		#region - Get XML Document -

		/// <summary>
		/// Gets an xml document for the active element
		/// </summary>
		/// <returns>XmlDocument with the active element parsed.</returns>
		private XmlDocument GetXMLDoc ()
		{
			string xmlToParse = this.ActiveElement.OuterHtml;
			int pos = 0;
			int parseIndex = xmlToParse.IndexOf('=', pos);
			while (parseIndex != -1)
			{
				if (xmlToParse[parseIndex + 1] != '\"')
				{
					xmlToParse = xmlToParse.Insert(parseIndex + 1, "\"");
					parseIndex = xmlToParse.IndexOf(' ', parseIndex);
					xmlToParse = xmlToParse.Insert(parseIndex, "\"");
				}
				pos = parseIndex + 1;
				parseIndex = xmlToParse.IndexOf('=', pos);
			}
			XmlDocument xDoc = new XmlDocument();
			xDoc.LoadXml(xmlToParse);
			return xDoc;
		}

        #endregion

		#region - Highlight Row -

		/// <summary>
        /// Highlightes the Row...
        /// </summary>
        private void HighlightRow (HtmlElement clickElement, bool ctrlKeyPressed, bool rightMouse)
        {
            HtmlElement elTable = this.GetParentElement(clickElement, "TABLE");
            if (elTable != null)
            {
                elTable = this.GetParentElement(clickElement, "TR");
                if (elTable == null)
                    return;
                if (elTable.FirstChild.TagName.Equals("TH"))
                    return;

                if (rightMouse && !string.IsNullOrEmpty(elTable.Style))
                    return;

                if (!ctrlKeyPressed)
                {
                    // Clear all Highlighting...
                    HtmlElementCollection hEls = this.Document.GetElementsByTagName("TR");
                    foreach (HtmlElement hel in hEls)
                    {
						if (!string.IsNullOrEmpty(hel.Style))
							hel.Style = "";
                    }
                }
                else if (!string.IsNullOrEmpty(elTable.Style))
                {
					elTable.Style = "";
                    return;
                }

				elTable.Style = "background: #C0CFE2;";
            }
		}

		#endregion

		#region - Get Parent Html Element -

		/// <summary>
        /// Gets the Parent Element with the desired tag...
        /// </summary>
        /// <param name="startEl">Starting Child Element.</param>
        /// <param name="wantedTag">Tag of Desired Parent</param>
        /// <returns>Parent Element.</returns>
        public HtmlElement GetParentElement (HtmlElement startEl, string wantedTag)
        {
            if (startEl == null)
                return null;

            HtmlElement el = startEl;
            while (!el.TagName.Equals(wantedTag))
            {
                if (el.Parent == null)
                    return null;
                el = el.Parent;
            }

            return el;
		}

		#endregion

		#region - Strongs Tool Tip -

		/// <summary>
        /// Creates a tool Tip with the given strong's number.
        /// </summary>
        /// <param name="e">HtmlElementEventArgs.</param>
        /// <param name="num">Strongs Number.</param>
		/// <param name="horg">Original Html Text.</param>
		/// <param name="mouseOver">If we are in mouse over mode, this makes sure the  tool will close if already shown.</param>
        private void CreateStrongsTT (HtmlElementEventArgs e, string num, string horg, bool mouseOver)
        {
            if (mouseOver)
            {
                if (this.m_TTShown)
                {
                    if (this.m_MOToolTip.Tag.ToString().Equals(e.ToElement.InnerText))
                    {
                        return;
                    }
                    this.m_MOToolTip.Close();
                    this.m_MOToolTip.Dispose();
                    this.m_MOToolTip = null;
                    this.m_TTShown = false;
                }
            }
            foreach (cJData.icDBInfo dbI in this.m_FormMain.ProgramData.ReferenceDatabases)
            {
                if (dbI.Name.StartsWith("Strong's " + horg))
                {
                    Database db = new Database(Common.DATA_FOLDER + dbI.Path);
                    Query qBookList = new Query(QueryType.SELECT, Common.TABLE_BOOK_LIST);
                    qBookList.SELECT("*");
                    db.RunQuery(qBookList);

                    for (int b = 0; b < qBookList.RowsReturned; b++)
                    {
                        string table = qBookList.Results.GetFieldString(0, b);
                        Query q = new Query(QueryType.SELECT, table);
                        q.SELECT("*");
                        q.WHERE("Notes", Operator.EQUALS, num);

                        db.RunQuery(q);

                        if (q.RowsReturned > 0)
                        {
                            StringBuilder html = new StringBuilder();
                            html.Append("<table><tr><td>");
                            html.Append(q.Results.GetFieldString(1, 0));
                            html.Append("</td></tr></table>");
                            if (mouseOver)
                            {
                                this.m_TTShown = true;

                                this.m_MOToolTip = new fHtmlToolTip(this.m_FormMain, this.PointToScreen(e.ClientMousePosition),
                                    html.ToString(), q.Results.GetFieldString(0, 0) + " (" + num + ")", false);
                                this.m_MOToolTip.Tag = e.ToElement.InnerText;
                                this.m_MOToolTip.ShowTT();
                            }
                            else
                            {
                                fHtmlToolTip tt = new fHtmlToolTip(this.m_FormMain, this.PointToScreen(e.ClientMousePosition),
                                    html.ToString(), q.Results.GetFieldString(0, 0) + " (" + num + ")", true);
                                tt.ShowTT();
                            }
                            break;
                        }

                    }
                    break;
                }
            }
        }

        #endregion

        #region - Scripture ToolTip -

        /// <summary>
        /// Creates a tool tip for the clicked element.
        /// </summary>
        /// <param name="e">HtmlElementEventArgs</param>
        private void CreateScriptureTT (HtmlElementEventArgs e)
        {
            this.CloseTT();
            //StringBuilder sb = GetPassageText(this.ActiveElement);

            fHtmlToolTip tt = GetPassageText(this.ActiveElement, e.ClientMousePosition, true); 
            //new fHtmlToolTip(this.m_FormMain, this.PointToScreen(e.ClientMousePosition), sb.ToString(), this.ActiveElement.InnerText, true);
            tt.ShowTT();
        }

        /// <summary>
        /// Creates a tool tip for the given element.
        /// </summary>
        /// <param name="e">Html Element to create Tool Tip for.</param>
		/// <param name="eAr">HtmlElementEventArgs</param>
        private void CreateMOScriptureTT (HtmlElement e, HtmlElementEventArgs eAr)
        {
            if (this.m_TTShown)
            {
                if (this.m_MOToolTip.Title.Equals(e.InnerText))
                {
                    return;
                }
                this.m_MOToolTip.Close();
                this.m_MOToolTip.Dispose();
                this.m_MOToolTip = null;
                this.m_TTShown = false;
            }

            this.m_TTShown = true;
            //StringBuilder sb = GetPassageText(e);

            this.m_MOToolTip = GetPassageText(e, eAr.ClientMousePosition, false); /*new fHtmlToolTip(this.m_FormMain, this.PointToScreen(eAr.ClientMousePosition), sb.ToString(),
                e.InnerText, false);*/
            this.m_MOToolTip.ShowTT();
        }

        #endregion

        #region - Get Passage Text -

		/// <summary>
		/// Gets the text for the passage in question...
		/// </summary>
		/// <param name="e">HtmlElement with corresponding passage(s).</param>
        /// <param name="pos">Position to place tool tip.</param>
        /// <param name="closebutton">True to add a close button to the tool tip.</param>
        /// <returns>Newly created Tool Tip</returns>
        private fHtmlToolTip GetPassageText (HtmlElement e, Point pos, bool closebutton)
        {
            List<cPassage> passages = cParser.Parse(e.InnerText);

            string path = "";
            string source = "";
            if (this.m_Host != null)
            {
                path = this.m_Host.GetVersionPath(-1);
                source = this.m_Host.GetVersion(-1);
            }

            if (string.IsNullOrEmpty(path))
            {
                // Get the Cell...
                HtmlElement elTD = this.ActiveElement;
                while (!elTD.TagName.Equals("TD"))
                {
                    if (elTD.Parent == null)
                        return null;
                    elTD = elTD.Parent;
                }
                int index = 0;
                if ((index = elTD.OuterHtml.IndexOf("version=")) != -1)
                {
                    path = elTD.OuterHtml.Substring(index + 9, elTD.OuterHtml.IndexOf(">") - 10 - index);
                    source = this.m_Host.GetVersion(Convert.ToInt32(path));
                    path = this.m_Host.GetVersionPath(Convert.ToInt32(path));
                }
            }

            Database db = null;
            if (this.m_Host == null || string.IsNullOrEmpty(path))
            {
                db = new Database(this.m_FormMain.DefaultBibleFile);
                source = this.m_FormMain.ProgramData.DefaultBible;
            }
            else
            {
                db = new Database(path);
            }

            StringBuilder sb = Common.GetToolTipText(passages, source, db);

            fHtmlToolTip tt = new fHtmlToolTip(this.m_FormMain, this.PointToScreen(pos), sb.ToString(), e.InnerText, closebutton);
            tt.SetVersionPath(path);
            return tt;
            //return sb;
        }

        #endregion

        #region - Public Properties -

        /// <summary>
        /// Gets the Active Element that was Clicked...
        /// </summary>
        public HtmlElement MouseClickElement
        {
            get { return this.m_MouseClickElement; }
        }

        /// <summary>
        /// Gets the current selection.
        /// </summary>
        public string Selection
        {
            get 
			{
				return this.Document.InvokeScript("getTextSelection").ToString().Trim();
			}
        }

        /// <summary>
        /// Gets or Sets the Inner HTML of the document.
        /// </summary>
        public string innerHTML
        {
            get { return this.Document.Body.InnerHtml; }
            set { this.Document.Body.InnerHtml = value; }
        }

        /// <summary>
        /// Gets or Sets the Inner Text of the Document.
        /// </summary>
        public string innerTEXT
        {
            get { return this.Document.Body.InnerText; }
            set { this.Document.Body.InnerText = value; }
        }

        /// <summary>
        /// Gets or Sets the HTML of the document giving the ability to use CSS and scripts.
        /// </summary>
        public string HTML
        {
            get { return this.m_HTML; }

            set
            {
                this.m_HTML = value;
				this.Document.OpenNew(true);
				this.Document.Write(value);
				this.Document.InvokeScript("resizeJonathan");
                /* Old Code using mshtml to load a web document. This makes javascript work automatically!
				 * mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)this.Document.DomDocument;
                 * doc.write(value);
                 * doc.close();*/
            }
        }

        /// <summary>
        /// Gets the Body of the document.
        /// </summary>
        public HtmlElement Body
        {
            get { return this.Document.Body; }
        }

        /// <summary>
        /// Gets the Active Element of the document.
        /// </summary>
        public HtmlElement ActiveElement
        {
            get { return this.Document.ActiveElement; }
        }

        #endregion

        #region - Public Methods -

        /// <summary>
        /// Select the word clicked.
        /// </summary>
        public void SelectWord()
		{
			this.Document.InvokeScript("expandSelection");
        }

        /// <summary>
        /// Clear any selection.
        /// </summary>
        public void ClearSelection()
		{
			this.Document.ExecCommand("Unselect", false, null);
        }

        /// <summary>
        /// Copy Current Selection.
        /// </summary>
        public void Copy()
        {
            this.Document.ExecCommand("Copy", false, null);
            ClearSelection();
        }

        /// <summary>
        /// Paste data from the clipboard.
        /// </summary>
        public void Paste()
        {
            this.Document.ExecCommand("Paste", false, null);
        }

        /// <summary>
        /// Cut Current Selection.
        /// </summary>
        public void Cut()
        {
            this.Document.ExecCommand("Cut", false, null);
        }

        /// <summary>
        /// Select Everything in the Document.
        /// </summary>
        public void SelectAll()
        {
            this.Document.ExecCommand("SelectAll", false, null);
		}

		/// <summary>
		/// Finds occurances of the given text.
		/// </summary>
		/// <param name="text">Text to find.</param>
		/// <returns>Found or not Found</returns>
		public void FindNext (string text)
		{
			this.Document.InvokeScript("findString", new object[] { text });
		}

        /// <summary>
        ///  Highlight All occurances of the given text.
        /// </summary>
        /// <param name="text">Text to highlight.</param>
        /// <param name="caseSensitive">Is h</param>
        public void Highlight(string text, bool caseSensitive)
        {
            StringBuilder html = new StringBuilder();
            string tempHtml = (caseSensitive) ? this.Document.Body.InnerHtml : this.Document.Body.InnerHtml.ToLower();
            if (!caseSensitive)
                text = text.ToLower();

            int start = 0;
            int lastFind = 0;
            while ((start = tempHtml.IndexOf(text, start)) != -1)
            {
                html.Append(this.innerHTML.Substring(lastFind, start - lastFind));
                html.Append("<span style=\"background: yellow;\">");
                html.Append(this.innerHTML.Substring(start, text.Length));
                html.Append("</span>");
                start += text.Length;
                lastFind = start;
            }

            html.Append(this.innerHTML.Substring(lastFind, this.innerHTML.Length - lastFind));
            this.Document.Body.InnerHtml = html.ToString();
        }

        #endregion
    }
}
